#include "ImgFcn.h"

ImgFcn::ImgFcn(QImage *m_Img1)
{
    m_Img = m_Img1;
    /*
    qDebug()<<"*********Red";
    for(int y = 0; y<m_Img->height(); y++)
    {
        QRgb * line = (QRgb *)m_Img->scanLine(y);
        for(int x = 0; x<m_Img->width(); x++)
        {
            cout<<qRed(line[x])<<"  ";
        }
        cout<<std::endl;
    }
    qDebug()<<"*********Green";
    for(int y = 0; y<m_Img->height(); y++)
    {
        QRgb * line = (QRgb *)m_Img->scanLine(y);
        for(int x = 0; x<m_Img->width(); x++)
        {
            cout<<qGreen(line[x])<<"  ";
        }
        cout<<std::endl;
    }
    qDebug()<<"*********Blue";
    for(int y = 0; y<m_Img->height(); y++)
    {
        QRgb * line = (QRgb *)m_Img->scanLine(y);
        for(int x = 0; x<m_Img->width(); x++)
        {
            cout<<qBlue(line[x])<<"  ";
        }
        cout<<std::endl;
    }

    */

    /*
    vector<vector<double>> Img = {{3,3,2,1,0},{0,0,1,3,1},{3,1,2,2,3},{2,0,0,2,2},{2,0,0,0,1}};
    vector<vector<int>> Kernel = {{0,1,2},{2,2,0},{0,1,2}};

    for (int y = 0; y<Img.size(); y++) {
        for (int x = 0;x<Img[0].size(); x++) {
            cout<<Img[y][x]<<"  ";
        }
        cout<<std::endl;
    }
    qDebug()<<"********************";
    for (int y = 0; y<Kernel.size(); y++) {
        for (int x = 0;x<Kernel[0].size(); x++) {
            cout<<Kernel[y][x]<<"  ";
        }
        cout<<std::endl;
    }
    qDebug()<<"********************";

    vector<vector<double>> xx = imgCovn(Img, {Kernel, Standard, 3, 3}, {1, 1});
    PoolRes yy = imgPool(Img, {Max, 2, 2}, {2, 2});
    vector<vector<double>> zz = imgDecPool(yy.PoolImg, yy.PoolTemp);
    */
}

vector<vector<double>> ImgFcn::imgCovn(vector<vector<double>> Img, ConvKernel convKernel, Stride stride)
{   //默认标准卷积 水平竖直步长为1
    int height = Img.size();
    int width = Img[0].size();
    vector<vector<int>> Kernel = convKernel.Kernel;
    int size = convKernel.X;

    int StrideX = stride.X;
    int StrideY = stride.Y;

    //卷积核尺寸 奇数 一半尺寸+-来计算邻域
    int halfSize = (size - 1) / 2;
    //输出尺寸
    int outputWidth = 0;
    int outputHeight = 0;
    //中间结果 最开始并不知道输出的尺寸，因此采取原始的大小
    vector<vector<double>> localRes = Img;

    for (int y = 0; y<height; y = y+StrideY) {
        outputHeight ++;
        outputWidth = 0;
        for (int x = 0;x<width; x = x+StrideX) {
            outputWidth ++;
            //计算邻域  模板叠加相加
            double outputPix = 0.0;
            for (int i = -halfSize; i<halfSize+1; i++) {
                if(((y+i)<0) || ((y+i)>(height-1))) continue; //行越界
                for (int j = -halfSize; j<halfSize+1; j++) {
                    if(((x+j)<0) || ((x+j)>(width-1))) continue;//列越界

                    double thisPix = Img[y+i][x+j];
                    double thisKernel = Kernel[i+halfSize][j+halfSize];
                    outputPix = outputPix + thisPix * thisKernel;
                }
            }
            localRes[outputHeight-1][outputWidth-1] = outputPix;
        }
    }

    //知道最终大小后  输出结果
    vector<vector<double>> res;
    res.resize(outputHeight);
    for (int i = 0; i<res.size();i++) {
        res[i].resize(outputWidth);
    }

    for (int y = 0; y<outputHeight; y++) {
        for (int x = 0; x<outputWidth; x++) {
            res[y][x] = localRes[y][x];
        }
    }

    qDebug()<<"****** Covn Operation ******";
    qDebug()<<"input:W*H:"<<width<<"*"<<height;
    qDebug()<<"with kernel:"<<size<<" and Stride X*Y:"<<StrideX<<"*"<<StrideY;
    qDebug()<<"output W*H:"<<outputWidth<<"*"<<outputHeight;
    /*
    qDebug()<<"result:";
    for (int y = 0; y<res.size(); y++) {
        for (int x = 0;x<res[0].size(); x++) {
            cout<<res[y][x]<<"  ";
        }
        cout<<std::endl;
    }
    */
    qDebug()<<"********* Covn END *********";

    return res;
}

PoolRes ImgFcn::imgPool(vector<vector<double>> Img, PoolKernel poolKernel, Stride stride)
{
    int height = Img.size();
    int width = Img[0].size();

    //输出尺寸
    int outputWidth = 0;
    int outputHeight = 0;
    //中间结果 最开始并不知道输出的尺寸，因此采取原始的大小
    vector<vector<double>> localRes = Img;
    vector<vector<double>> poolModel = Img;
    for (int y = 0; y<poolModel.size(); y++) {
        for (int x = 0;x<poolModel[0].size(); x++) {
            poolModel[y][x] = 0;
        }
    }
    //滤波器的尺寸
    int FilterX = poolKernel.X;
    int FilterY = poolKernel.Y;
    //移动的步长
    int StrideX = stride.X;
    int StrideY = stride.Y;

    for (int y = 0; y<height; y = y+StrideY) {
        outputHeight ++;
        outputWidth = 0;
        for (int x = 0;x<width; x = x+StrideX) {
            outputWidth ++;
            //计算邻域  模板叠加相加
            double outputPix = 0.0;
            for (int i = 0; i<FilterY; i++) {
                if(((y+i)<0) || ((y+i)>(height-1))) continue; //行越界
                for (int j = 0; j<FilterX; j++) {
                    if(((x+j)<0) || ((x+j)>(width-1))) continue;//列越界

                    double thisPix = Img[y+i][x+j];
                    if(thisPix > outputPix) outputPix = thisPix;
                }
            }
            localRes[outputHeight-1][outputWidth-1] = outputPix;

            for (int ii = 0; ii<FilterY; ii++) {
                if(((y+ii)<0) || ((y+ii)>(height-1))) continue; //行越界
                for (int jj = 0; jj<FilterX; jj++) {
                    if(((x+jj)<0) || ((x+jj)>(width-1))) continue;//列越界
                    if(Img[y+ii][x+jj] == outputPix) poolModel[y+ii][x+jj] = 1;
                }
            }
        }
    }

    //知道最终大小后  输出结果
    vector<vector<double>> res;
    res.resize(outputHeight);
    for (int i = 0; i<res.size();i++) {
        res[i].resize(outputWidth);
    }

    for (int y = 0; y<outputHeight; y++) {
        for (int x = 0; x<outputWidth; x++) {
            res[y][x] = localRes[y][x];
        }
    }

    qDebug()<<"****** Pool Operation ******";
    qDebug()<<"input:W*H:"<<width<<"*"<<height;
    qDebug()<<"with Filter:"<<FilterX<<"*"<<FilterY<<" and Stride X*Y:"<<StrideX<<"*"<<StrideY;
    qDebug()<<"output W*H:"<<outputWidth<<"*"<<outputHeight;
    /*
    qDebug()<<"result:";
    for (int y = 0; y<res.size(); y++) {
        for (int x = 0;x<res[0].size(); x++) {
            cout<<res[y][x]<<"  ";
        }
        cout<<std::endl;
    }
    qDebug()<<"poolModel:";
    for (int y = 0; y<poolModel.size(); y++) {
        for (int x = 0;x<poolModel[0].size(); x++) {
            cout<<poolModel[y][x]<<"  ";
        }
        cout<<std::endl;
    }
    */
    qDebug()<<"********* Pool END *********";

    PoolRes poolRes = {res, poolModel};
    return poolRes;
}

vector<vector<double>> ImgFcn::imgDecPool(vector<vector<double>> PoolImg, vector<vector<double>> PoolTemp, PoolKernel poolKernel)
{
    vector<vector<double>> res = PoolTemp;
    //滤波器大小
    int FilterX = poolKernel.X;
    int FilterY = poolKernel.Y;

    for (int y = 0; y < PoolImg.size(); y++) {
        for (int x = 0; x < PoolImg[0].size(); x++) {
            //其区域
            for (int i = 0; i<FilterY; i++) {
                for (int j = 0; j<FilterX; j++) {
                    if((y*FilterY+i)>PoolTemp.size()-1) continue;
                    if((x*FilterX+j)>PoolTemp[0].size()-1) continue;
                    if(PoolTemp[y*FilterY+i][x*FilterX+j] == 1){
                        res[y*FilterY+i][x*FilterX+j] = PoolImg[y][x];
                    }
                }
            }
        }
    }

    qDebug()<<"****** DecPool Operation ******";
    qDebug()<<"input:W*H:"<<PoolImg[0].size()<<"*"<<PoolImg.size();
    qDebug()<<"with Filter:"<<FilterX<<"*"<<FilterY;
    qDebug()<<"output W*H:"<<res[0].size()<<"*"<<res.size();
    /*
    qDebug()<<"result:";
    for (int y = 0; y<res.size(); y++) {
        for (int x = 0;x<res[0].size(); x++) {
            cout<<res[y][x]<<"  ";
        }
        cout<<std::endl;
    }
    */
    qDebug()<<"********* DecPool END *********";

    return res;
}

vector<vector<double>> ImgFcn::fcn(vector<vector<double>> Img)
{
    //2n*2n单通道图像
    vector<vector<int>> Kernel = {{-1,-1,-1},{-1,8,-1},{-1,-1,-1}};
    //1、图像预处理
    //1、第一层卷积 池化 变为1/2尺寸
    qDebug("&&&&&&& covn 1 &&&&&&&");
    vector<vector<double>> covn1 = imgCovn(Img, {Kernel, Standard, 3, 3}, {1, 1});
    PoolRes pool1 = imgPool(covn1, {Max, 2, 2}, {2, 2});
    //2、第二层卷积 池化 变为1/4尺寸
    qDebug("&&&&&&& covn 2 &&&&&&&");
    vector<vector<double>> covn2 = imgCovn(pool1.PoolImg, {Kernel, Standard, 3, 3}, {1, 1});
    PoolRes pool2 = imgPool(covn2, {Max, 2, 2}, {2, 2});
    //3、第三层卷积 池化 变为1/8尺寸
    qDebug("&&&&&&& covn 3 &&&&&&&");
    vector<vector<double>> covn3 = imgCovn(pool2.PoolImg, {Kernel, Standard, 3, 3}, {1, 1});
    PoolRes pool3 = imgPool(covn3, {Max, 2, 2}, {2, 2});
    //4、第四层卷积 池化 变为1/16尺寸
    qDebug("&&&&&&& covn 4 &&&&&&&");
    vector<vector<double>> covn4 = imgCovn(pool3.PoolImg, {Kernel, Standard, 3, 3}, {1, 1});
    PoolRes pool4 = imgPool(covn4, {Max, 2, 2}, {2, 2});
    //5、第五层卷积 池化 变为1/32尺寸
    qDebug("&&&&&&& covn 5 &&&&&&&");
    vector<vector<double>> covn5 = imgCovn(pool4.PoolImg, {Kernel, Standard, 3, 3}, {1, 1});
    PoolRes pool5 = imgPool(covn5, {Max, 2, 2}, {2, 2});

    //反池化5 变为1/16
    qDebug("------- decpool 5 -------");
    vector<vector<double>> decPool5 = imgDecPool(pool5.PoolImg, pool5.PoolTemp);
    //decPool5+pool4
    vector<vector<double>> dec54 = decPool5;
    for (int y = 0; y<dec54.size(); y++) {
        for (int x = 0; x<dec54[0].size(); x++) {
            dec54[y][x] = decPool5[y][x] + pool4.PoolImg[y][x];
        }
    }
    //反池化4 变为1/8
    qDebug("------- decpool 4 -------");
    vector<vector<double>> decPool4 = imgDecPool(dec54, pool4.PoolTemp);
    //decPool4+pool3
    vector<vector<double>> dec43 = decPool4;
    for (int y = 0; y<dec43.size(); y++) {
        for (int x = 0; x<dec43[0].size(); x++) {
            dec43[y][x] = decPool4[y][x] + pool3.PoolImg[y][x];
        }
    }
    //反池化3 变为1/4
    qDebug("------- decpool 3 -------");
    vector<vector<double>> decPool3 = imgDecPool(dec43, pool3.PoolTemp);
    //decPool3+pool2
    vector<vector<double>> dec32 = decPool3;
    for (int y = 0; y<dec32.size(); y++) {
        for (int x = 0; x<dec32[0].size(); x++) {
            dec32[y][x] = decPool3[y][x] + pool2.PoolImg[y][x];
        }
    }
    //反池化2 变为1/2
    qDebug("------- decpool 2 -------");
    vector<vector<double>> decPool2 = imgDecPool(dec32, pool2.PoolTemp);
    //decPool3+pool2
    vector<vector<double>> dec21 = decPool2;
    for (int y = 0; y<dec21.size(); y++) {
        for (int x = 0; x<dec21[0].size(); x++) {
            dec21[y][x] = decPool2[y][x] + pool1.PoolImg[y][x];
        }
    }
    //反池化1 变为1/1
    qDebug("------- decpool 1 -------");
    vector<vector<double>> decPool1 = imgDecPool(dec21, pool1.PoolTemp);

    return decPool1;
    //vector<vector<double>> zz = imgDecPool(yy.PoolImg, yy.PoolTemp);
}

QImage *ImgFcn::imgFCN()
{
    QImage *newImg = new QImage(m_Img->width(), m_Img->height(), QImage::Format_ARGB32);
    //初始化 RGB 分量
    vector<vector<double>> R;
    R.resize(m_Img->height());
    for (int y = 0; y<R.size(); y++) {
        R[y].resize(m_Img->width());
    }
    vector<vector<double>> G = R;
    vector<vector<double>> B = R;

    //提取出RGB
    for(int y = 0; y<m_Img->height(); y++)
    {
        QRgb * line = (QRgb *)m_Img->scanLine(y);
        for(int x = 0; x<m_Img->width(); x++)
        {
            R[y][x] = double(qRed(line[x]));
            G[y][x] = double(qGreen(line[x]));
            B[y][x] = double(qBlue(line[x]));
        }
    }

    //分别开始计算
    qDebug()<<"R";
    vector<vector<double>> resR = fcn(R);
    qDebug()<<"G";
    vector<vector<double>> resG = fcn(G);
    qDebug()<<"B";
    vector<vector<double>> resB = fcn(B);

    //合成RGB
    for(int y = 0; y<m_Img->height(); y++)
    {
        QRgb * line = (QRgb *)m_Img->scanLine(y);
        for(int x = 0; x<m_Img->width(); x++)
        {
            newImg->setPixel(x,y, qRgb(int(resR[y][x]), int(resG[y][x]), int(resB[y][x])));
        }
    }

    return newImg;
}
